/*
Eteria IRC Client, an RFC 1459 compliant client program written in Java.
Copyright (C) 2000-2001  Javier Kohen <jkohen at tough.com>

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

import java.awt.*;
import java.awt.event.*;
import java.io.IOException;
import java.util.Enumeration;
import java.net.URL;
import java.net.MalformedURLException;


import ar.com.jkohen.awt.*;
import ar.com.jkohen.awt.event.*;
import ar.com.jkohen.irc.Channel;
import ar.com.jkohen.irc.RFC1459;
import ar.com.jkohen.util.Resources;
import ar.com.jkohen.util.CollatedHashtable;

public class ChatPanelContainer extends Panel implements ActionListener, MouseListener, TextListener
{
    private EIRC eirc;
    private Resources res;

    private CollatedHashtable panels;
    private String status_tag;
    private String tab_under_menu;
    private ChatPanel visible_panel;

    private CardLayout container_layout;
    private BorderedPanel container;
    private ChatTabs tabs;
    private PopupMenu tabs_popup;
    private MenuItem close_item;
    private ImageCanvas label;
    private BorderedPanel bottom_panel;
    private ImageButton shift_left;
    private ImageButton shift_right;
    
    public ChatPanelContainer(EIRC eirc)
    {
    	this.eirc = eirc;
    	this.panels = new CollatedHashtable(RFC1459.getCollator());

    	GridBagLayout gb = new GridBagLayout();
    	GridBagConstraints gbc = new GridBagConstraints();

    	setLayout(gb);

    	this.container = new BorderedPanel();
    	gbc.weighty = 1.0;
    	gbc.weightx = 1.0;
    	gbc.fill = GridBagConstraints.BOTH;
    	gb.setConstraints(container, gbc);
    	add(container);
    	gbc.weightx = 0.0;
    	gbc.weighty = 0.0;

    	gbc.gridy = 1;

    	bottom_panel = new BorderedPanel(res.getString("bottom_panel"));
    	GridBagLayout bottom_gb = new GridBagLayout();
    	GridBagConstraints bottom_gbc = new GridBagConstraints();
    	bottom_panel.setLayout(bottom_gb);

    	/* Bottom Panel begins here. */
    	bottom_gbc.anchor = GridBagConstraints.NORTH;

		Image i = res.getImage("tabs.logo");
		if (i != null)
		{
			label = new ImageCanvas(i);
			bottom_gbc.gridheight = GridBagConstraints.REMAINDER;
			bottom_gb.setConstraints(label, bottom_gbc);
			bottom_panel.add(label);
			bottom_gbc.gridheight = 1;
		}

      	this.tabs = new ChatTabs(eirc);
    	bottom_gbc.weightx = 1.0;
    	bottom_gbc.fill = GridBagConstraints.HORIZONTAL;
    	bottom_gbc.gridheight = GridBagConstraints.REMAINDER;
    	bottom_gb.setConstraints(tabs, bottom_gbc);
    	bottom_panel.add(tabs);
    	bottom_gbc.gridheight = 1;
    	bottom_gbc.fill = GridBagConstraints.NONE;
    	bottom_gbc.weightx = 0.0;

    	this.shift_left = new ImageButton(false);
    	shift_left.setEnabled(false);
    	shift_left.setIcon(res.getImage("tabs.icon.shift_left"));
    	bottom_gb.setConstraints(shift_left, bottom_gbc);
    	bottom_panel.add(shift_left);

    	bottom_gbc.gridy = 1;

    	this.shift_right = new ImageButton(false);
    	shift_right.setEnabled(false);
		shift_right.setIcon(res.getImage("tabs.icon.shift_right"));
    	bottom_gb.setConstraints(shift_right, bottom_gbc);
    	bottom_panel.add(shift_right);
    	
    	/* Bottom Panel ends here. */

    	gbc.weightx = 1.0;
    	gbc.fill = GridBagConstraints.HORIZONTAL;
    	gb.setConstraints(bottom_panel, gbc);
    	add(bottom_panel);

    	tabs.setImage(ChatTabs.CHAN, ChatTabs.NORMAL, ChatTabs.LEFT, res.getImage("tabs.normal.chan"));
    	tabs.setImage(ChatTabs.CHAN, ChatTabs.NORMAL, ChatTabs.CENTER, res.LARGE_NORMAL);
    	tabs.setImage(ChatTabs.CHAN, ChatTabs.CURRENT, ChatTabs.LEFT, res.getImage("tabs.current.chan"));
    	tabs.setImage(ChatTabs.CHAN, ChatTabs.CURRENT, ChatTabs.CENTER, res.LARGE_PRESSED);
    	tabs.setImage(ChatTabs.CHAN, ChatTabs.ALARM, ChatTabs.LEFT, res.getImage("tabs.alarm.chan"));
    	tabs.setImage(ChatTabs.CHAN, ChatTabs.ALARM, ChatTabs.CENTER, res.LARGE_ALERT);

    	tabs.setImage(ChatTabs.PRIV, ChatTabs.NORMAL, ChatTabs.LEFT, res.getImage("tabs.normal.private"));
    	tabs.setImage(ChatTabs.PRIV, ChatTabs.NORMAL, ChatTabs.CENTER, res.LARGE_NORMAL);
    	tabs.setImage(ChatTabs.PRIV, ChatTabs.CURRENT, ChatTabs.LEFT, res.getImage("tabs.current.private"));
    	tabs.setImage(ChatTabs.PRIV, ChatTabs.CURRENT, ChatTabs.CENTER, res.LARGE_PRESSED);
    	tabs.setImage(ChatTabs.PRIV, ChatTabs.ALARM, ChatTabs.LEFT, res.getImage("tabs.alarm.private"));
    	tabs.setImage(ChatTabs.PRIV, ChatTabs.ALARM, ChatTabs.CENTER, res.LARGE_ALERT);
    	
    	tabs.setImage(ChatTabs.SERV, ChatTabs.NORMAL, ChatTabs.LEFT, res.getImage("tabs.normal.server"));
    	tabs.setImage(ChatTabs.SERV, ChatTabs.NORMAL, ChatTabs.CENTER, res.LARGE_NORMAL);
    	tabs.setImage(ChatTabs.SERV, ChatTabs.CURRENT, ChatTabs.LEFT, res.getImage("tabs.current.server"));
    	tabs.setImage(ChatTabs.SERV, ChatTabs.CURRENT, ChatTabs.CENTER, res.LARGE_PRESSED);
    	tabs.setImage(ChatTabs.SERV, ChatTabs.ALARM, ChatTabs.LEFT, res.getImage("tabs.alarm.server"));
    	tabs.setImage(ChatTabs.SERV, ChatTabs.ALARM, ChatTabs.CENTER, res.LARGE_ALERT);
    	
    	this.container_layout = new CardLayout();
    	container.setLayout(container_layout);

		MenuItem mi = null;
    	this.tabs_popup = new PopupMenu();
    	mi = new MenuItem(res.getString("close.privates"));
    	mi.setActionCommand("close.privates");
    	tabs_popup.add(mi);
		mi = new MenuItem(res.getString("close.channels"));
    	mi.setActionCommand("close.channels");
    	tabs_popup.add(mi);
    	add(tabs_popup);
		
		tabs_popup.addSeparator();
		
    	mi = new MenuItem(res.getString("open"));
    	mi.setActionCommand("open");
    	tabs_popup.add(mi);
    	this.close_item = new MenuItem(res.getString("close"));
    	close_item.setActionCommand("close");
    	tabs_popup.add(close_item);
		
		if (label != null)
			label.addMouseListener(this);
			
    	tabs.addActionListener(this);
    	tabs.addMouseListener(this);
    	shift_left.addActionListener(this);
    	shift_right.addActionListener(this);
    	tabs_popup.addActionListener(this);
    }

    public void add(ChatPanel cp, String tag)
    {
		add(cp, tag, false);
    }

    public void add(ChatPanel cp, String tag, boolean is_status)
    {
		if (is_status)
		{
		    if (status_tag != null)
		    {
				throw new IllegalArgumentException("already have a status panel");
		    }
	    	this.status_tag = tag;
		}

		synchronized (this)
		{
			panels.put(tag, cp);
			container.add(cp, tag.toLowerCase());
			tabs.add(tag);
		}

		updateShiftButtons();

		cp.addTextListener(this);
    }

    public void addPanel(ChatPanel cp, String tag)
    {
		synchronized (this)
		{
			panels.put(tag, cp);
			container.add(cp, tag.toLowerCase());
		}

		cp.addTextListener(this);
    }
    
    public synchronized void showPanel(String tag)
    {
		ChatPanel cp = this.visible_panel = (ChatPanel) panels.get(tag);
		
		container_layout.show(container, tag.toLowerCase());
		cp.requestFocus();
		tabs.notVisible();
		
		container.setTag(cp.getTitle());
    }
    
    public void remove(String tag)
    {
		if (tag.equals(visible_panel))
		    this.visible_panel = null;

		synchronized (this)
		{
	    	tabs.remove(tag);
	    	
	    	Component c = (Component) panels.remove(tag);
			if (c == null) return;
	    	container.remove(c);

		    if (tag.equals(status_tag))
				this.status_tag = null;

		    String new_tab = tabs.getCurrent();
		    if (new_tab != null)
		    {
				show(new_tab);
		    }
		    else if (panels.containsKey(status_tag))
		    {
				show(status_tag);
		    }
		}

		updateShiftButtons();
    }

    public synchronized void rename(String old_tag, String tag)
    {
		ChatPanel cp = (ChatPanel) panels.get(old_tag);

		// Removing the old panel isn't necessary: adding it under a different tag has the same effect.
		container.add(cp, tag.toLowerCase());
		if (old_tag.equals(tabs.getVisible()))
			container_layout.show(container, tag.toLowerCase());

		cp.setPanelTag(tag);
		panels.put(tag, cp);
		panels.remove(old_tag);

		tabs.rename(old_tag, tag);
    }

    public void setTitle(String tag, String title)
    {
    	ChatPanel cp = (ChatPanel)panels.get(tag);
    	cp.setTitle(title);
    	
    	if(this.visible_panel == cp)
    		container.setTag(title);
    }
    
    public synchronized void show(String tag)
    {
		ChatPanel cp = this.visible_panel = (ChatPanel)panels.get(tag);

		container_layout.show(container, tag.toLowerCase());
		cp.requestFocus();

		tabs.setAlarm(tag, false);
		tabs.makeVisible(tag);
		
		container.setTag(cp.getTitle());
    }

    private void updateShiftButtons()
    {
		int tabs_width = tabs.getSize().width;
		boolean enabled = tabs_width > 0 && tabs_width < tabs.getPreferredSize().width;

		shift_left.setEnabled(enabled);
		shift_right.setEnabled(enabled);
    }

    public ChatPanel getVisible()
    {
		return visible_panel;
    }

    public void setFont(Font f)
    {
		super.setFont(f);
		container.setFont(f);
		bottom_panel.setFont(f);
  		tabs.setFont(f);
		
		// Popup menu font
		for (int i = 0; i < tabs_popup.getItemCount(); i++)
			tabs_popup.getItem(i).setFont(f);
    }
    
    public void setForeground(Color c)
    {
		super.setForeground(c);
		container.setForeground(c);
		bottom_panel.setForeground(c);
  		tabs.setForeground(c);
  		if(label != null)
  			label.setForeground(c);
    }

    public void setBackground(Color c)
    {
		super.setBackground(c);
		container.setBackground(c);
		bottom_panel.setBackground(c);
  		tabs.setBackground(c);
  		if(label != null)
	  		label.setBackground(c);
		shift_left.setBackground(c);
		shift_right.setBackground(c);
    }

    public void setBounds(int x, int y, int w, int h)
    {
		super.setBounds(x, y, w, h);
		updateShiftButtons();
    }

    public void actionPerformed(ActionEvent ev)
    {
		Object source = ev.getSource();

		if (source.equals(tabs))
		{
	    	show(ev.getActionCommand());
		}
		else if (source.equals(shift_left))
		{
	    	tabs.shiftLeft();
		}
		else if (source.equals(shift_right))
		{
	    	tabs.shiftRight();
		}
		else if (source instanceof MenuItem)
		{
	    	String cmd = ev.getActionCommand();

	    	if (cmd.equals("open"))
	    	{
				show(tab_under_menu);
	    	}
	    	else if (cmd.equals("close"))
	    	{
				ChatPanel cp = (ChatPanel) panels.get(tab_under_menu);
				if (cp != null)
				{
					if (Channel.isChannel(tab_under_menu))
					{
						String p[] = { tab_under_menu };
						eirc.sendMessage("PART", p);
						eirc.closeChannel(tab_under_menu);
					}
				} 
			}
			else if (cmd.equals("close.privates"))
	    	{
				eirc.closePrivates();
			}
			else if (cmd.equals("close.channels"))
	    	{
				eirc.closeChannels();
			}
		}
    }
	
    public void mouseClicked(MouseEvent ev)
    {
    }

    public void mouseReleased(MouseEvent ev)
    {
    }

    public void mousePressed(MouseEvent ev)
    {
        Object source = ev.getSource();

		if (source.equals(tabs))
		{
	    	if (ev.isPopupTrigger() || 0 != (ev.getModifiers() & MouseEvent.BUTTON3_MASK))
	    	{
	    		// WORKAROUND: #27 MSIE doesn't set popupTrigger.
				String tab = tabs.getTabAt(ev.getPoint());
				if (tab != null)
				{
					tab_under_menu = tab;

					// Disable "close" item for status panel.
					close_item.setEnabled(!tab.equals(status_tag));

					tabs_popup.show(tabs, ev.getX(), ev.getY());
				}
			}
		}

		if (source.equals(label))
		{
			try
			{
				eirc.visitURL(new URL(res.getLabel("tabs.url")));
 			}
			catch (MalformedURLException e) {}
		}
    }

    public void mouseEntered(MouseEvent ev)
    {
		Object source = ev.getSource();
		if (source.equals(label))
			setCursor(new Cursor(Cursor.HAND_CURSOR));
    }

    public void mouseExited(MouseEvent ev)
    {
		setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
    }

    public void textValueChanged(TextEvent e)
	{
		ChatPanel cp = (ChatPanel) e.getSource();
		String tag = cp.getPanelTag();

		// Don't try to set an alarm on a recently closed panel.
		synchronized (this)
		{
	    	if (panels.containsKey(tag))
				tabs.setAlarm(tag, true);
		}
    }
}
